package com.mcc.app.workflow.service.impl;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.mcc.app.workflow.domain.WfMetaInfo;
import com.mcc.app.workflow.domain.WfModel;
import com.mcc.app.workflow.service.IWfModelService;
import com.mcc.app.workflow.utils.ModelUtils;
import com.mcc.common.exception.CustomException;
import com.mcc.common.utils.SecurityUtils;
import com.mcc.common.utils.StringUtils;
import org.activiti.bpmn.model.BpmnModel;
import org.activiti.bpmn.model.Process;
import org.activiti.bpmn.model.StartEvent;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.repository.Model;
import org.activiti.engine.repository.ModelQuery;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;

@Service
public class WfModelServiceImpl implements IWfModelService {

    @Autowired
    private RepositoryService repositoryService;

    @Override
    public List<WfModel> selectModelList(WfModel wfModel) {
        ModelQuery modelQuery = repositoryService.createModelQuery();
        modelQuery.orderByModelKey().asc().orderByModelVersion().asc().orderByLastUpdateTime().asc();
        if (ObjectUtil.isNotEmpty(modelQuery)) {
            if (StrUtil.isNotBlank(wfModel.getModelKey()))
                modelQuery.modelKey(wfModel.getModelKey());
            if (StrUtil.isNotBlank(wfModel.getModelName()))
                modelQuery.modelNameLike("%" + wfModel.getModelName() + "%");
            if (StrUtil.isNotBlank(wfModel.getCategory()))
                modelQuery.modelCategory(wfModel.getCategory());
        }
        List<Model> list = modelQuery.list();
        List<WfModel> res = new ArrayList<>();
        for (int i = 0; i < list.size(); i++) {
            Model model = list.get(i);
            WfModel row = new WfModel();
            row.setId(model.getId());
            row.setModelKey(model.getKey());
            row.setModelName(model.getName());
            row.setCategory(model.getCategory());
            row.setVersion(model.getVersion());
            row.setCreateDt(model.getCreateTime());
            row.setUpdateDt(model.getLastUpdateTime());
            WfMetaInfo metaInfo = JSONUtil.toBean(model.getMetaInfo(), WfMetaInfo.class);
            if (metaInfo != null) {
                row.setCreateUser(metaInfo.getCreateUser());
            }
            res.add(row);
        }
        return res;
    }

    @Override
    public WfModel selectModelById(String id) {
        WfModel res = new WfModel();
        Model model = repositoryService.getModel(id);
        if (model != null) {
            res.setId(model.getId());
            res.setModelKey(model.getKey());
            res.setModelName(model.getName());
            res.setCategory(model.getCategory());
            res.setVersion(model.getVersion());
            res.setCreateDt(model.getCreateTime());
            res.setUpdateDt(model.getLastUpdateTime());
            res.setBpmnXml(queryBpmnXmlById(model.getId()));
            WfMetaInfo metaInfo = JSONUtil.toBean(model.getMetaInfo(), WfMetaInfo.class);
            if (metaInfo != null) {
                res.setCreateUser(metaInfo.getCreateUser());
            }
        }
        return res;
    }

    @Override
    public String queryBpmnXmlById(String modelId) {
        byte[] bpmnBytes = repositoryService.getModelEditorSource(modelId);
        return StrUtil.utf8Str(bpmnBytes);
    }

    @Override
    public String saveModel(WfModel wfModel) {
        BpmnModel bpmnModel = ModelUtils.getBpmnModel(wfModel.getBpmnXml());
        if (ObjectUtil.isEmpty(bpmnModel)) {
            throw new CustomException("获取模型设计失败！");
        }
        // 获取开始节点
        StartEvent startEvent = ModelUtils.getStartEvent(bpmnModel);
        if (ObjectUtil.isNull(startEvent)) {
            throw new CustomException("开始节点不存在，请检查流程设计是否有误！");
        }
        Process process = bpmnModel.getMainProcess();

        boolean isExist = false;
        //判断是否已有
        Model model = repositoryService.getModel(wfModel.getId());
        if (model == null) {
            //如果有最新版本，就在最新版本上更新
            model = repositoryService.createModelQuery().modelKey(process.getId()).latestVersion().singleResult();
            if (model == null) model = repositoryService.newModel();
            else isExist = true;
        } else {
            isExist = true;
        }
        //新版本创建
        if (isExist) {
            if (wfModel.getNewVersion()) {
                model = repositoryService.newModel();
                Model latestModel = repositoryService.createModelQuery().modelKey(process.getId()).latestVersion().singleResult();
                if (latestModel != null) {
                    model.setVersion(latestModel.getVersion() + 1);
                }
            }
        }
        model.setKey(process.getId());
        model.setName(process.getName());
        model.setCategory(wfModel.getCategory());
        if (!wfModel.getNewVersion()) {
            model.setVersion(wfModel.getVersion());
        }
        WfMetaInfo metaInfo = new WfMetaInfo();
        metaInfo.setCreateUser(SecurityUtils.getUsername());
        model.setMetaInfo(JSONUtil.toJsonStr(metaInfo));
        repositoryService.saveModel(model);
        byte[] bpmnXmlBytes = StringUtils.getBytes(wfModel.getBpmnXml(), StandardCharsets.UTF_8);
        repositoryService.addModelEditorSource(model.getId(), bpmnXmlBytes);
        return model.getId();
    }

    @Override
    @Transactional
    public boolean deleteModelByIds(String[] ids) {
        if (ids.length == 0) return false;
        for (int i = 0; i < ids.length; i++) {
            repositoryService.deleteModel(ids[i]);
        }
        return true;
    }
}
